<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head th:replace="_fragments :: header(~{::title})">
    <title th:text="${blog.title}">windanchaos的博客</title>
    <link rel="stylesheet" type="text/css" href="../static/semantic.min.css" th:href="@{/semantic.min.css}">
    <script
            src="https://code.jquery.com/jquery-3.1.1.min.js" th:src="@{/jquery-3.1.1.min.js}"
            integrity="sha256-hVVnYaiADRTO2PzUGmuLJr8BLUSjGIZsDYGmIJLv2b8="
            crossorigin="anonymous"></script>
    <script src="../static/semantic.min.js" th:src="@{/semantic.min.js}"></script>
    <meta charset="UTF-8">
</head>
<body>
<!--
1、menu的大小不知道怎么控制，加huge等无效
2、博客列表的边框线不知道怎么操作让其消失
3、顶部菜单栏的浮动效果，没有研究js怎么操作（js操作的理解为高级功能，不接触）

-->
    <div class="ui borderless main menu " th:replace="_fragments::menu(1,blue)">
        <div class="ui huge text container">
            <a class="item" href="#" th:href="@{/}">
                <i class="home icon" ></i> 主页
            </a>
            <a class="item" href="category.html" th:href="@{/category}">
                <i class="folder icon"></i> 分类
            </a>
            <a class="item" href="archive.html" th:href="@{/archive}">
                <i class="archive icon"></i> 归档
            </a>
            <a class="item" href="tags.html" th:href="@{/tags}">
                <i class="tags icon"></i> 标签
            </a>
            <div class="ui simple green dropdown item">
                更多
                <i class="dropdown icon"></i>
                <div class="menu">
                    <a class="item"><i class="chess king icon"></i> 关于作者</a>
                    <a class="item"><i class="language icon"></i> 选择语言</a>
                    <a class="item"><i class="settings icon"></i> 账号设置</a>
                </div>
            </div>
            <div class="right item">
                <div class="ui icon input">
                    <input type="text" placeholder="搜索...">
                    <i class="search icon"></i>
                </div>
            </div>
        </div>
    </div>
    <div class="ui borderless grid">
            <div class="ui two wide column"></div>
            <div class="ui eleven wide column" >
                <div class="ui container">
                    <div class="ui raised segment">
                        <h2 class="ui header blue" th:text="${blog.title}">一种VPN自动设置的解决方案</h2>
                        <div class="ui">
                            <div class="ui label" >发布时间:<time th:text="${#dates.format(blog.create_time,'yyyy-MM-dd hh:mm:ss')}">2020/04/01 13:30</time></div>
                            <div class="ui label">分类:<span th:each="category:${categories.getCategoriesByArticleID(blog.id)}" ><a href="#" th:href="@{'/category/' + ${category.id}}" th:text="' | '+${category.name} +' | '">持续集成</a> </span></div>
                            <div class="ui label">阅读数:23</div>
                        </div>
                        <div class="ui divider"></div>
                        <div id="testEditormdView2">
                            <textarea id="append-test" style="display:none;" th:text="${blog.content}">

                                将之前写过的一个小工具做了一些优化，开源出来。起了个没有任何意义的ppter。
                                将之前写过的一个小工具做了一些优化，开源出来。起了个没有任何意义的ppter。

                                ppter概述
                                为什么叫ppter
                                任性，没有意义，听着挺好听，嗯就这样。

                                项目地址： https://github.com/windanchaos/ppter

                                可用场景
                                多地办公，没有固定IP，需办公区对办公区建立VPN，办公区和阿里云建立VPN的场景。

                                能节省的费用就是两条固定IP的费用。拒我了解的一个固定IP的电信一年30万左右，移动的要10来万。对于小公司来说，一年还是能节约不少钱了。

                                市面上的其他解决方案，我并不太清楚，如果有更优的免费方案，欢迎告知。

                                文件说明
                                aliapi.py 阿里云部分产品api的封装
                                ConfigProvider.py 配置相关，读取config.ini转成需要的数据类型
                                Jobs.py 运行的进程
                                Dockerfile docker image镜像构建文件
                                requirement 项目依赖
                                config.ini 配置相关
                                getDnsInfo.py 获取域名解析信息工具
                                ppter_vpn.py vpn相关代码
                                ppter_vps.py vps相关代码
                                ppter_dns.py dns解析相关
                                工作原理
                                使用独立于办公区内部环境的阿里云（或其他共有云），部署redis作为ip交换媒介。
                                clip_image001
                                前置动作
                                修改正确的config.ini
                                修改正确vpn配置
                                具体参考下文。

                                容器安装
                                docker的安装和配置优化
                                其中user是可以操作docker的普通账户，换成自己的即可

                                script
                                bash installDocker.sh user
                                监控程序启动操作
                                镜像打包
                                docker build -t dns_monitor .
                                启动容器进程
                                docker run -it -d -v `pwd`/config.ini:/root/config.ini --name monitor dns_monitor
                                直接安装
                                使用的python3。

                                依赖安装
                                sudo pip3 install redis request configparser base64
                                执行
                                不同环境独立执行：

                                nohup python3 Jobs.py > log.log &
                                程序会做以下动作：

                                5分钟定时获取一次外网IP地址，并同步到redis上
                                对比IP地址是否有变化，有就执行dns解析、阿里云ipes、本地路由vpn配置变更。ip地址包括本地ip变化和连接端的ip变动。A和B的IP任意变动都会触发本地路由vpn配置。
                                启动前需要修改的配置
                                config.ini的文件内容，大部分顾名思义。

                                Credentials
                                需要配置具有阿里云vps 、dns操作权限的id和secret。

                                域名解析的配置
                                [dns] 下的domain设置

                                一个｛’RecordId’:’xxx’,’RR’:’record’｝就是一条记录

                                用’|’符号作分隔符。多条记录：｛’RecordId’:’4154842768102400’,’RR’:’recordA’｝|｛’RecordId’:’4154842768102400’,’RR’:’recordB’｝

                                其中RR标识map.baidu.com 中的map。

                                按规则添加即可，删除也是

                                如何获取domain的recordId和RR（主机记录）？

                                python3 getDnsInfo.py
                                执行后会打印‘baidu.com’的所有解析信息。复制粘贴到json在线解析，找到需要的解析信息。

                                如果要换域名就修改getDnsInfo.py的内容。

                                vpn的设置
                                前三个参数是路由器的登录地址和账户密码。

                                redisLocalVpnName 是redis中IP地址的本地标识。

                                redisRemoteVpnName 是vpn连接远端的标识。

                                A、B环境的名字需要互换。

                                A环境的配置：

                                redisLocalVpnName = A
                                redisRemoteVpnName = B
                                B环境的配置：

                                redisLocalVpnName = B
                                redisRemoteVpnName = A
                                vpn 的配置数据这里没有做到配置文件中，在updata_vpn.py中修改vpn_data，默认vpn-config[0]是对阿里云的vpn设置。vpn-config[1:]之后的是本地对本地的设置。
                                这类数据可能不同路由器，值是不一样的。需要自己去抓包了解一下了。

                                VPS设置
                                不同环境名字区别开即可。

                                详细的配置在update_vps.py中，主要修改CreateVpnConnection参数。

                                CreateVpnConnection = {'Action': 'CreateVpnConnection', 'RegionId': 'cn-hangzhou',
                                'VpnGatewayId': 'XXXXXXX', \
                                'LocalSubnet': '172.16.128.0/20', 'RemoteSubnet': '10.189.51.0/24',
                                'IpsecConfig':str({'IpsecAuthAlg':'sha1'}),
                                'IkeConfig': str({'Psk': 'XXXXXXX','IkeAuthAlg': 'sha1'}), 'CustomerGatewayId': '', 'Name': ''}
                                网关的名字是设置的name取第二个字符（不含）之后的字符，比如现在name为tohzh，则对应网关名hzh。

                                Psk 要设置成自己定义的值。

                                特别注意，用户网关如果没有和ipsce关联，就不要提前设置，否则无法新建。

                                开源小总结
                                1、requests类库是个优秀的开发语言级别的“浏览器”库，基本上不用费神去操作cookies之类的，畅快的request就好；

                                2、程序持续运行，异常抛出后继续运行的机制设置对程序进程稳定性很重要，异常抛出一般接不住就用所有异常类父类：BaseException

                                3、学会了一项新的技能，在服务器上控制台上做调试。可参考这篇文章。

                                python3 -m pdb test.py
                                如果要简单说，下面wsn三个我用了比较实用。我在码代码过程中，遇到一个问题，始终不知道为什么在服务器上运行失败，而本地是ok的。调试后发现是配置文件没有换（服务器上是请求url有单引号，解析不出来）
                                w：（where）打印当前执行堆栈

                                s：（step）执行下一条命令

                                n：（next）执行下一条语句

                                4、docker是个好东西

                                5、扒拉一个系统的运行过程，才能结合自己的需求去做优化和修改。
                            </textarea>
                        </div>
                    </div>
                </div>

            </div>
            <div class="ui three wide column"></div>
        </div>
<!-- <script src="js/zepto.min.js"></script>
<script>
    var jQuery = Zepto;  // 为了避免修改flowChart.js和sequence-diagram.js的源码，所以使用Zepto.js时想支持flowChart/sequenceDiagram就得加上这一句
</script> -->
<script th:src="@{/lib/marked.min.js}"></script>
<script th:src="@{/lib/prettify.min.js}"></script>

<script th:src="@{/lib/raphael.min.js}"></script>
<script th:src="@{/lib/underscore.min.js}"></script>
<script th:src="@{/lib/sequence-diagram.min.js}"></script>
<script th:src="@{/lib/flowchart.min.js}"></script>
<script th:src="@{/lib/jquery.flowchart.min.js}"></script>

<script th:src="@{/editormd.min.js}"></script>

<script type="text/javascript">
    $(function () {
        editormd.markdownToHTML("testEditormdView2", {
            htmlDecode: "style,script,iframe",  // you can filter tags decode
            emoji: true,
            taskList: true,
            tex: true,  // 默认不解析
            flowChart: true,  // 默认不解析
            sequenceDiagram: true,  // 默认不解析
        });
    });
</script>
</body>
</html>